package com.jxpanda.spring.module.auth.config;


import com.jxpanda.spring.module.auth.config.properties.AuthConfigProperties;
import com.jxpanda.spring.module.auth.config.properties.RegistrationProperties;
import com.jxpanda.spring.module.auth.core.OAuth2StrategyFactory;
import com.jxpanda.spring.module.auth.core.authentication.strategy.AbstractCollaborativeReactiveAuthenticationStrategy;
import com.jxpanda.spring.module.auth.core.authentication.strategy.CollaborativeReactiveAuthenticationOAuth2StrategyResolver;
import com.jxpanda.spring.module.auth.core.authentication.strategy.CollaborativeReactiveAuthenticationStrategy;
import com.jxpanda.spring.module.auth.core.register.strategy.OAuth2ReactiveRegisterStrategy;
import com.jxpanda.spring.module.auth.core.register.strategy.OAuth2ReactiveRegisterStrategyResolver;
import com.jxpanda.spring.module.auth.endpoint.GrantType;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;

@RequiredArgsConstructor
public class StrategyConfigure {

    private final AuthConfigProperties authConfigProperties;

    private final OAuth2StrategyFactory oAuth2StrategyFactory;


    @Bean
    @ConditionalOnMissingBean
    public ReactiveClientRegistrationRepository reactiveClientRegistrationRepository() {
        return new InMemoryReactiveClientRegistrationRepository(this.authConfigProperties.getClientRegistrations());
    }

    @Bean
    @ConditionalOnMissingBean
    public OAuth2ReactiveRegisterStrategyResolver oAuth2ReactiveRegisterStrategyResolver() {
        OAuth2ReactiveRegisterStrategyResolver resolver = new OAuth2ReactiveRegisterStrategyResolver();
        this.authConfigProperties.getClientRegistrations()
                .forEach(it -> {
                    String clientId = it.getClientId();
                    GrantType grantType = GrantType.of(it.getAuthorizationGrantType().getValue());
                    String repositoryBeanName = it.getProviderDetails()
                            .getConfigurationMetadata()
                            .getOrDefault(RegistrationProperties.REPOSITORY_BEAN_NAME_KEY, "")
                            .toString();
                    OAuth2ReactiveRegisterStrategy registerStrategy = oAuth2StrategyFactory
                            .createRegisterStrategy(grantType, repositoryBeanName);
                    resolver.putStrategy(clientId, registerStrategy);
                });
        return resolver;
    }

    @Bean
    @ConditionalOnMissingBean
    public CollaborativeReactiveAuthenticationOAuth2StrategyResolver collaborativeReactiveAuthenticationStrategyResolver() {
        CollaborativeReactiveAuthenticationOAuth2StrategyResolver resolver = new CollaborativeReactiveAuthenticationOAuth2StrategyResolver();
        this.authConfigProperties.getClientRegistrations().forEach(it -> {
            String clientId = it.getClientId();
            GrantType grantType = GrantType.of(it.getAuthorizationGrantType().getValue());
            String repositoryBeanName = it.getProviderDetails()
                    .getConfigurationMetadata()
                    .getOrDefault(RegistrationProperties.REPOSITORY_BEAN_NAME_KEY, "")
                    .toString();
            CollaborativeReactiveAuthenticationStrategy authenticationStrategy =
                    oAuth2StrategyFactory.createAuthenticationStrategy(grantType, repositoryBeanName);
            if (authenticationStrategy == null) {
                throw new IllegalArgumentException("认证策略自动配置失败，授权类型：" + grantType + "暂不支持，请手动配置。");
            }
            resolver.putStrategy(it.getClientId(), authenticationStrategy);
        });
        return resolver;
    }


}
